package com.etone.smartAudit.service;

import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.etone.smartAudit.domain.Admin;
import com.etone.smartAudit.domain.DataMeta;
import com.etone.smartAudit.domain.DataModel;
import com.etone.smartAudit.dto.dataModel.DataModelDTO;
import com.etone.smartAudit.dto.iapDataMeta.IapDataMetaDTO;
import com.etone.smartAudit.dto.iapDataModel.IapDataModelDTO;
import com.etone.smartAudit.enums.AccountType;
import com.etone.smartAudit.enums.DataBaseType;
import com.etone.smartAudit.enums.OpenType;
import com.etone.smartAudit.enums.UseState;
import com.etone.smartAudit.error.CustomParameterizedException;
import com.etone.smartAudit.mapper.DataModelMapper;
import com.etone.smartAudit.mapstruct.DataModelMapstruct;
import com.etone.smartAudit.mapstruct.IapDataMetaMapstruct;
import com.etone.smartAudit.utils.database.DatabaseUtil;
import com.etone.smartAudit.vo.FileVO;
import com.etone.smartAudit.vo.PagerVO;
import com.etone.smartAudit.vo.accountInfo.AccountInfoVO;
import com.etone.smartAudit.vo.dataMeta.DataMetaVO;
import com.etone.smartAudit.vo.dataModel.DataModelDetailVO;
import com.etone.smartAudit.vo.dataModel.DataModelListVO;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;

/**
 * @author: sovy
 * @date: 2020/11/10
 * @description:
 */

@Service
@AllArgsConstructor
public class DataModelService extends ServiceImpl<DataModelMapper, DataModel> {

    private DataModelMapstruct dataModelMapstruct;

    private DataMetaService dataMetaService;

    private AdminPermissionService adminPermissionService;

    private AccountInfoService accountInfoService;

    private IapDataMetaMapstruct iapDataMetaMapstruct;

    private IapDataModelService iapDataModelService;

    private FileUploadService fileUploadService;


    /**
     * 获取公共数据
     *
     * @param admin
     * @param modelName
     * @param level3Ids
     * @param databaseName
     * @param itemId
     * @param passiveItemId 被授权项目id
     * @param isAuth        是否授权
     * @param page
     * @param pageSize
     * @return
     */
    public PagerVO<DataModelListVO> listPublic(Admin admin, String modelName, List<Integer> level3Ids, String databaseName, Integer itemId, Integer passiveItemId, Boolean isAuth, int page, int pageSize) {
        Page<DataModelListVO> dataModelListVOPage = PageHelper.startPage(page, pageSize).doSelectPage(() -> baseMapper.findList(admin.getId(), modelName, level3Ids, databaseName, itemId, passiveItemId, isAuth, OpenType.PUBLIC));
        return PagerVO.of(dataModelListVOPage);
    }

    /**
     * 获取私有数据
     *
     * @param admin
     * @param modelName
     * @param level3Ids
     * @param databaseName
     * @param itemId
     * @param page
     * @param pageSize
     * @return
     */
    public PagerVO<DataModelListVO> listPrivate(Admin admin, String modelName, List<Integer> level3Ids, String databaseName, Integer itemId, int page, int pageSize) {
        Page<DataModelListVO> dataModelListVOPage = PageHelper.startPage(page, pageSize).doSelectPage(() -> baseMapper.findPrivateList(admin.getId(), modelName, level3Ids, databaseName, itemId));
        return PagerVO.of(dataModelListVOPage);
    }

    /**
     * 数据模型授权审核通过
     *
     * @param itemId
     * @param dataModelIds
     */
    public void auditPass(Integer itemId, List<Integer> dataModelIds) {
        if (itemId == null || CollectionUtils.isEmpty(dataModelIds)) {
            return;
        }
        baseMapper.addDataModelAuth(itemId, dataModelIds);

        //同步到审计知识库元数据

        //自动执行授权
        List<DataModel> dataModels = baseMapper.selectBatchIds(dataModelIds);
        if (!CollectionUtils.isEmpty(dataModels)) {
            dataModels.forEach(dataModel -> {

                //被授权项目信息
                AccountInfoVO toAutItemDatabase = accountInfoService.get(dataModel.getServerId(), itemId, AccountType.valueOf(dataModel.getDataBaseType().name()), null);

                //授权项目信息
                AccountInfoVO autItemDatabase = accountInfoService.get(dataModel.getServerId(), dataModel.getItemId(), AccountType.valueOf(dataModel.getDataBaseType().name()), null);

                //执行授权
                DatabaseUtil.authTableSelect(dataModel.getServerIp(), autItemDatabase.getAccount(), autItemDatabase.getPassword(), autItemDatabase.getPort(), dataModel.getDatabaseName(), dataModel.getSchemaName(), dataModel.getEnTableName(), toAutItemDatabase.getAccount(), dataModel.getDataBaseType());

            });

        }

    }

    /**
     * 模型详情
     *
     * @param id
     * @return
     */
    public DataModel get(Integer id) {
        DataModel dataModel = getById(id);
        if (dataModel == null) {
            throw new CustomParameterizedException("数据模型不存在");
        }
        return dataModel;
    }

    /**
     * 判断模型是否存在
     *
     * @param id
     * @return
     */
    public boolean exists(Integer id) {
        LambdaQueryWrapper<DataModel> queryWrapper = new LambdaQueryWrapper();
        queryWrapper.eq(DataModel::getId, id);
        int count = count(queryWrapper);
        if (count == 0) {
            throw new CustomParameterizedException("数据模型不存在");
        }
        return count > 0;
    }

    /**
     * 查询私有数据权限
     *
     * @param id
     * @param adminId
     */
    public void checkPrivateData(Integer id, Integer adminId) {
        boolean checkResult = baseMapper.checkPrivateData(id, adminId);
        if (!checkResult) {
            throw new CustomParameterizedException("您没有权限");
        }
    }

    /**
     * 模型详情
     *
     * @param id
     * @param admin
     * @return
     */
    public DataModelDetailVO detail(Integer id, Admin admin) {
        DataModel dataModel = getById(id);

        //私有数据校验权限
        if (dataModel.getOpenType().equals(OpenType.PRIVATE)) {
            checkPrivateData(id, admin.getId());
        }

        return dataModelMapstruct.getDataModelDetailVO(dataModel);
    }

    /**
     * 编辑|保存数据模型
     *
     * @param id
     * @param admin
     * @param dataModelDTO
     */
    @Transactional(rollbackFor = Exception.class)
    public void save(Integer id, Admin admin, DataModelDTO dataModelDTO) {
        DataModel dataModel;
        if (id == null) {
            dataModel = DataModel
                    .builder()
                    .createAdminId(admin.getId())
                    .createAdminName(admin.getNickName())
                    .createTime(new Date())
                    .openType(OpenType.PRIVATE)
                    .build();
            dataModelMapstruct.copy2DataModel(dataModel, dataModelDTO);

            AccountInfoVO accountInfo = accountInfoService.get(dataModelDTO.getServerId(), dataModelDTO.getItemId(), AccountType.valueOf(dataModelDTO.getDataBaseType().name()), null);

            dataModel.setDatabaseName(accountInfo.getDatabaseName());
            dataModel.setSchemaName(accountInfo.getSchemaName());

            //检查表名是否存在
            checkTableNameExistsThrow(dataModel.getItemId(), dataModel.getServerId(), dataModel.getDatabaseName(), dataModel.getSchemaName(), dataModel.getEnTableName(), dataModel.getDataBaseType());

            save(dataModel);

            //添加后的操作
            doAddAfter(dataModel.getId(), dataModelDTO, accountInfo);

            fileUploadService.deleteFileForUpdate(dataModelDTO.getDataExamples(), null);
        } else {
            DataModel dataModelFlag = get(id);
            String dataExamples = dataModelFlag.getDataExamples();

            if (dataModelFlag.getOpenType().equals(OpenType.PRIVATE)) {
                checkPrivateData(id, admin.getId());
            } else if (!adminPermissionService.hasPermission(admin, "edit_data_model_public")) {
                throw new CustomParameterizedException("您没有权限编辑");
            }
            dataModel = DataModel
                    .builder()
                    .id(id)
                    .platformId(dataModelDTO.getPlatformId())
                    .updateFreq(dataModelDTO.getUpdateFreq())
                    .psvCycle(dataModelDTO.getPsvCycle())
                    .level1(dataModelDTO.getLevel1())
                    .level2(dataModelDTO.getLevel2())
                    .level3(dataModelDTO.getLevel3())
                    .level1Id(dataModelDTO.getLevel1Id())
                    .level2Id(dataModelDTO.getLevel2Id())
                    .level3Id(dataModelDTO.getLevel3Id())
                    .description(dataModelDTO.getDescription())
                    .dataExamples(CollectionUtils.isEmpty(dataModelDTO.getDataExamples()) ? "[]" : JSONArray.toJSONString(dataModelDTO.getDataExamples()))
                    .build();
            updateById(dataModel);
            fileUploadService.deleteFileForUpdate(dataModelDTO.getDataExamples(), StringUtils.isEmpty(dataExamples) ? null : JSONArray.parseArray(dataExamples, FileVO.class));
        }

    }

    /**
     * 同一个项目，同一台服务器，同一个数据库，同一个schema，检查表名是否存在
     *
     * @param itemId
     * @param serverId
     * @param database
     * @param schema
     * @param tableName
     * @param dataBaseType
     * @return
     */
    public boolean checkTableNameExists(Integer itemId, Integer serverId, String database, String schema, String tableName, DataBaseType dataBaseType) {
        return baseMapper.checkTableNameExists(itemId, serverId, database, schema, tableName, dataBaseType);
    }

    /**
     * 同一个项目，同一台服务器，同一个数据库，同一个schema，检查表名是否存在
     *
     * @param itemId
     * @param serverId
     * @param database
     * @param schema
     * @param tableName
     * @param dataBaseType
     * @return
     */
    public void checkTableNameExistsThrow(Integer itemId, Integer serverId, String database, String schema, String tableName, DataBaseType dataBaseType) {
        if (checkTableNameExists(itemId, serverId, database, schema, tableName, dataBaseType)) {
            throw new CustomParameterizedException("英文表名称已存在");
        }
    }

    /**
     * 创建模型
     *
     * @param dataModelId
     * @param dataModelDTO
     * @param accountInfo
     */
    public void doAddAfter(Integer dataModelId, DataModelDTO dataModelDTO, AccountInfoVO accountInfo) {
        //保存元数据
        List<DataMeta> dataMetas = dataMetaService.save(dataModelId, dataModelDTO.getDataMetas());
        //建表
        DatabaseUtil.createTable(accountInfo.getServerIp(), accountInfo.getAccount(), accountInfo.getPassword(), accountInfo.getPort(), accountInfo.getDatabaseName(), accountInfo.getSchemaName(), dataModelDTO.getEnTableName(), dataMetas, dataModelDTO.getDataBaseType());
    }

    /**
     * 删除
     *
     * @param id
     * @param admin
     */
    @Transactional(rollbackFor = Exception.class)
    public void delete(Integer id, Admin admin) {
        checkPrivateData(id, admin.getId());
        DataModel dataModel = get(id);
        removeById(id);
        doAfterDelete(dataModel);
    }

    /**
     * 批量删除
     *
     * @param ids
     * @param admin
     */
    @Transactional(rollbackFor = Exception.class)
    public void batchDelete(List<Integer> ids, Admin admin) {
        ids.forEach(id -> delete(id, admin));
    }

    /**
     * 删除后操作
     *
     * @param dataModel
     */
    public void doAfterDelete(DataModel dataModel) {
        dataMetaService.deleteByDateModelId(dataModel.getId());

        //删除真实表
        AccountInfoVO accountInfo = accountInfoService.get(dataModel.getServerId(), dataModel.getItemId(), AccountType.valueOf(dataModel.getDataBaseType().name()), null);
        DatabaseUtil.deleteTable(dataModel.getServerIp(), accountInfo.getAccount(), accountInfo.getPassword(), accountInfo.getPort(), dataModel.getDatabaseName(), dataModel.getSchemaName(), dataModel.getEnTableName(), dataModel.getDataBaseType());
    }

    /**
     * 模型共享
     *
     * @param ids
     */
    @Transactional(rollbackFor = Exception.class)
    public void toPublic(List<Integer> ids) {

        if (CollectionUtils.isEmpty(ids)) {
            throw new CustomParameterizedException("模型id不能为空");
        }
        //修改状态
        LambdaUpdateWrapper<DataModel> wrapper = new LambdaUpdateWrapper();
        wrapper.in(DataModel::getId, ids);
        wrapper.set(DataModel::getOpenType, OpenType.PUBLIC);
        update(wrapper);

        ids.forEach(id -> toPublic(id));
    }

    /**
     * 模型共享
     *
     * @param id
     */
    public void toPublic(Integer id) {
        DataModel dataModel = get(id);
        if (dataModel.getPlatformId() == null) {
            throw new CustomParameterizedException("请先完善" + dataModel.getEnTableName() + "(" + dataModel.getCnTableName() + ")系统平台");
        }
        //转IapDataModelDTO
        IapDataModelDTO iapDataModelDTO = dataModelMapstruct.getIapDataModelDTO(dataModel);
        if (iapDataModelDTO != null) {
            iapDataModelDTO.setUseState(UseState.USED);
            //获取元数据数据字典
            List<DataMetaVO> dataMetaVOS = dataMetaService.getBaseMapper().findList(id, null);
            if (!CollectionUtils.isEmpty(dataMetaVOS)) {
                List<IapDataMetaDTO> iapDataMetaDTOS = iapDataMetaMapstruct.getIapDataMetaDTO(dataMetaVOS);
                if (!CollectionUtils.isEmpty(iapDataMetaDTOS)) {
                    iapDataModelDTO.setIapDataMetas(iapDataMetaDTOS);
                }
            }
            iapDataModelService.save(null, iapDataModelDTO);
        }
    }

}

